﻿using Dapper;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Gear.ToolKits.Base.PageFactor;
using Gear.ToolKits.DbDriver;
using Gear.ToolKits.Extensions;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Gear.Application.Service.BaseService
{
    /// <summary>
    /// 增删查改父类（EF）
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TEntityInputDto"></typeparam>
    /// <typeparam name="TEntityUpdateDto"></typeparam>
    /// <typeparam name="TEntityDeleteDto"></typeparam>
    /// <typeparam name="TDbContextLocator"></typeparam>
    /// <typeparam name="TCondition"></typeparam>
    public class CurdService_EF<TEntity, TEntityInputDto, TEntityUpdateDto, TEntityDeleteDto, TDbContextLocator, TCondition>
        where TEntity : class, IPrivateEntity, new()
        where TDbContextLocator : class, IDbContextLocator
        where TCondition : PagedBaseDto
    {
        /// <summary>
        /// 注入仓储
        /// </summary>
        private readonly IRepository<TEntity, TDbContextLocator> _repository;

        /// <summary>
        /// 构造函数
        /// </summary>
        public CurdService_EF(IRepository<TEntity, TDbContextLocator> repository)
        {
            _repository = repository;
        }

        #region ==同步方法==

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public TEntity Insert(TEntityInputDto input) => _repository.Insert(input.Adapt<TEntity>()).Entity;

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public TEntity Update(TEntityUpdateDto input)=>_repository.Update(input.Adapt<TEntity>(), ignoreNullValues: true).Entity;

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public TEntity Delect(TEntityDeleteDto input) => _repository.Update(input.Adapt<TEntity>(), ignoreNullValues: true).Entity;
        /// <summary>
        /// 清除
        /// </summary>
        /// <param name="id"></param>
        public void Clear(int id) => _repository.Delete(id);

        /// <summary>
        /// 单条查询（根据主键）
        /// </summary>
        /// <param name="id"></param>
        public TEntity Find(int id)=> _repository.Find(id);

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public PagedList<TEntity> GetAllByPage(int pageIndex = 1, int pageSize = 10)=> _repository.AsQueryable(false).ProjectToType<TEntity>().ToPagedList(pageIndex, pageSize);

        /// <summary>
        /// 分页条件查询
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public PagedList<TEntity> GetSearch([FromQuery] TCondition input)
        {
            var result = new PagedList<TEntity>();

            var query = _repository.AsQueryable();
            var sourceExpression = query.Expression;

            
            if (input.Filters != null)
            {
                var Filters = JsonConvert.DeserializeObject<List<DataFilter>>(input.Filters);
                foreach (var filter in Filters)
                {
                    if (string.IsNullOrWhiteSpace(filter.FilterName) || string.IsNullOrWhiteSpace(filter.FilterValue))
                    {
                        continue;
                    }
                    var whereLambdaExtenstion = GetLambdaExtention(filter);
                    sourceExpression = Expression.Call(typeof(Queryable), "Where", new Type[1] { typeof(TEntity) }, sourceExpression, Expression.Quote(whereLambdaExtenstion.GetLambda()));

                }
            }
            if (input.Sorts != null)
            {
                var Sorts = JsonConvert.DeserializeObject<IList<DataSort>>(input.Sorts);
                ParameterExpression parameter = Expression.Parameter(typeof(TEntity), "x");
                string methodAsc = "OrderBy";
                string methodDesc = "OrderByDescending";
                foreach (var sort in Sorts)
                {
                    if (string.IsNullOrWhiteSpace(sort.SortName))
                    {
                        continue;
                    }
                    MemberExpression body = Expression.PropertyOrField(parameter, sort.SortName);
                    sourceExpression = Expression.Call(typeof(Queryable), sort.SortType == SortType.Asc ? methodAsc : methodDesc, new Type[] { typeof(TEntity), body.Type }, sourceExpression, Expression.Quote(Expression.Lambda(body, parameter)));
                    methodAsc = "ThenBy";
                    methodDesc = "ThenByDescending";
                }
            }

            //query = query.Provider.Execute<IEnumerable<TEntity>>(sourceExpression).AsQueryable();
            var data = query.Provider.Execute<IEnumerable<TEntity>>(sourceExpression).ToList();

            result.TotalCount = data.Count;
            if (input.PageSize != -1)
            {
                var res = data.Skip((input.PageIndex - 1) * input.PageSize).Take(input.PageSize);

                result.PageIndex = input.PageIndex;
                result.PageSize = input.PageSize;
                result.TotalPages %= input.PageSize;
                result.Items = res;
                result.HasPrevPages = input.PageIndex > 1 && input.PageIndex <= 2;
                result.HasNextPages = input.PageIndex < result.TotalPages;
            }
            else
            {
                result.PageIndex = input.PageIndex;
                result.PageSize = input.PageSize;
                result.TotalPages %= input.PageSize;
                result.Items = data;
                result.HasPrevPages = input.PageIndex > 1 && input.PageIndex <= 2;
                result.HasNextPages = input.PageIndex < result.TotalPages;
            }

            return result;
        }
        #endregion

        #region ==异步方法==

        /// <summary>
        /// 新增-异步
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<TEntity> InsertSync(TEntityInputDto input)
        {
            // 如果不需要返回自增Id，使用 InsertAsync即可
            var newEntity = await _repository.InsertNowAsync(input.Adapt<TEntity>());
            return newEntity.Entity;
        }

        /// <summary>
        /// 更新-异步
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<TEntity> UpdateSync(TEntityUpdateDto input)
        {
            var newEntity = await _repository.UpdateAsync(input.Adapt<TEntity>(), ignoreNullValues: true);
            return newEntity.Entity;
        }

        /// <summary>
        /// 删除-异步
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<TEntity> DelectSync(TEntityDeleteDto input)
        {
            var newEntity = await _repository.UpdateAsync(input.Adapt<TEntity>(), ignoreNullValues: true);
            return newEntity.Entity;
        }

        /// <summary>
        /// 清除-异步
        /// </summary>
        /// <param name="id"></param>
        public async Task<bool> ClearSync(int id)
        {
            await _repository.DeleteAsync(id);
            return true;
        }
        /// <summary>
        /// 单条查询-异步（根据主键）
        /// </summary>
        /// <param name="id"></param>
        public async Task<TEntity> FindSync(int id)
        {
            return await _repository.FindAsync(id);
        }

        /// <summary>
        /// 分页查询-异步
        /// </summary>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public async Task<PagedList<TEntity>> GetAllByPageSync(int pageIndex = 1, int pageSize = 10)
        {
            var pageResult = _repository.AsQueryable(false)
                                              .ProjectToType<TEntity>();

            return await pageResult.ToPagedListAsync(pageIndex, pageSize);
        }

        /// <summary>
        /// 分页条件查询-异步
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedList<TEntity>> GetSearchSync([FromQuery] TCondition input)
        {
            var result = new PagedList<TEntity>();

            var list =  await _repository.AsQueryable().ToListAsync();
            var query= list.AsQueryable();
            var sourceExpression = query.Expression;


            if (input.Filters != null)
            {
                var Filters = JsonConvert.DeserializeObject<List<DataFilter>>(input.Filters);
                foreach (var filter in Filters)
                {
                    if (string.IsNullOrWhiteSpace(filter.FilterName) || string.IsNullOrWhiteSpace(filter.FilterValue))
                    {
                        continue;
                    }
                    var whereLambdaExtenstion = GetLambdaExtention(filter);
                    sourceExpression = Expression.Call(typeof(Queryable), "Where", new Type[1] { typeof(TEntity) }, sourceExpression, Expression.Quote(whereLambdaExtenstion.GetLambda()));

                }
            }
            if (input.Sorts != null)
            {
                var Sorts = JsonConvert.DeserializeObject<IList<DataSort>>(input.Sorts);
                ParameterExpression parameter = Expression.Parameter(typeof(TEntity), "x");
                string methodAsc = "OrderBy";
                string methodDesc = "OrderByDescending";
                foreach (var sort in Sorts)
                {
                    if (string.IsNullOrWhiteSpace(sort.SortName))
                    {
                        continue;
                    }
                    MemberExpression body = Expression.PropertyOrField(parameter, sort.SortName);
                    sourceExpression = Expression.Call(typeof(Queryable), sort.SortType == SortType.Asc ? methodAsc : methodDesc, new Type[] { typeof(TEntity), body.Type }, sourceExpression, Expression.Quote(Expression.Lambda(body, parameter)));
                    methodAsc = "ThenBy";
                    methodDesc = "ThenByDescending";
                }
            }

            //query = query.Provider.Execute<IEnumerable<TEntity>>(sourceExpression).AsQueryable();
            var data = query.Provider.Execute<IEnumerable<TEntity>>(sourceExpression).ToList();

            result.TotalCount = data.Count;
            if (input.PageSize != -1)
            {
                var res = data.Skip((input.PageIndex - 1) * input.PageSize).Take(input.PageSize);

                result.Items = res;
            }
            else
            {
                result.Items = data;
            }

            return result;
        }

        #endregion

        #region ==工具==
        //Lambda表达式处理
        private static LambdaExtention<TEntity> GetLambdaExtention(DataFilter filter)
        {
            var whereLambdaExtenstion = new LambdaExtention<TEntity>();

            switch (filter.FilterType)
            {
                case FilterType.Int:
                    whereLambdaExtenstion.GetExpression(filter.FilterName, int.Parse(filter.FilterValue), filter.ExpressionType);
                    break;
                case FilterType.Long:
                    whereLambdaExtenstion.GetExpression(filter.FilterName, long.Parse(filter.FilterValue), filter.ExpressionType);
                    break;
                case FilterType.Boolean:
                    whereLambdaExtenstion.GetExpression(filter.FilterName, filter.FilterValue.ToUpper() == "TRUE", filter.ExpressionType);
                    break;
                default:
                    whereLambdaExtenstion.GetExpression(filter.FilterName, filter.FilterValue, filter.ExpressionType);
                    break;
            }
            return whereLambdaExtenstion;

        }
        #endregion
    }

    /// <summary>
    /// 增删查改父类（SqlSugar）
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TEntityInputDto"></typeparam>
    /// <typeparam name="TEntityUpdateDto"></typeparam>
    /// <typeparam name="TEntityDeleteDto"></typeparam>
    /// <typeparam name="TCondition"></typeparam>
    public class CurdService_Sugar<TEntity, TEntityInputDto, TEntityUpdateDto, TEntityDeleteDto, TCondition>
        where TEntity : class, IPrivateEntity, new()
        where TCondition : PagedBaseDto
    {
        /// <summary>
        /// 注入仓储
        /// </summary>
        private readonly ISqlSugarRepository _repository; // 仓储对象：封装简单的CRUD
        private readonly SqlSugarClient _db; // 核心对象：拥有完整的SqlSugar全部功能
        private readonly IAdo _dbAdo;// Ado重载对象 支持原生sql写法

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="sqlSugarRepository"></param>
        public CurdService_Sugar(ISqlSugarRepository sqlSugarRepository)
        {
            _repository = sqlSugarRepository;
            _db = _repository.Context;
            _dbAdo = _db.Ado;
        }

        #region == 同步 ==

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public int Insert(TEntityInputDto input)=> _db.Insertable<TEntity>(input).IgnoreColumns(ignoreNullColumn: true).ExecuteReturnIdentity();
        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public int Update(TEntityUpdateDto input) => _db.Updateable<TEntity>(input).ExecuteCommand();
        
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public int Delect(TEntityDeleteDto input) => _db.Updateable<TEntity>(input).ExecuteCommand();

        /// <summary>
        /// 清除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public int Clear(int id) => _db.Deleteable<TEntity>(id).ExecuteCommand();

        /// <summary>
        /// 单条查询（根据主键）
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public TEntity Find(int id)=> _db.Queryable<TEntity>().InSingle(id);
        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public PagedList<TEntity> GetAllByPage(int pageIndex = 1, int pageSize = 10)
        {
            int totalCount = 0;
            PagedList<TEntity> result = new();
            var data=_db.Queryable<TEntity>().ToPageList(pageIndex, pageSize, ref totalCount);
            result.PageIndex = pageIndex;
            result.PageSize = pageSize;
            result.TotalCount = totalCount;
            result.TotalPages = totalCount % pageSize;
            result.Items = data;
            result.HasPrevPages = pageIndex>1&& pageIndex<=2;
            result.HasNextPages = pageIndex< result.TotalPages;
            return result;
        }

        /// <summary>
        /// 分页条件查询
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public PagedList<TEntity> GetSearch([FromQuery] TCondition input)
        {
            var result = new PagedList<TEntity>();

            var query = _db.Queryable<TEntity>().ToList().AsQueryable();
            var sourceExpression = query.Expression;


            if (input.Filters != null)
            {
                var Filters = JsonConvert.DeserializeObject<List<DataFilter>>(input.Filters);
                foreach (var filter in Filters)
                {
                    if (string.IsNullOrWhiteSpace(filter.FilterName) || string.IsNullOrWhiteSpace(filter.FilterValue))
                    {
                        continue;
                    }
                    var whereLambdaExtenstion = GetLambdaExtention(filter);
                    sourceExpression = Expression.Call(typeof(Queryable), "Where", new Type[1] { typeof(TEntity) }, sourceExpression, Expression.Quote(whereLambdaExtenstion.GetLambda()));

                }
            }
            if (input.Sorts != null)
            {
                var Sorts = JsonConvert.DeserializeObject<IList<DataSort>>(input.Sorts);
                ParameterExpression parameter = Expression.Parameter(typeof(TEntity), "x");
                string methodAsc = "OrderBy";
                string methodDesc = "OrderByDescending";
                foreach (var sort in Sorts)
                {
                    if (string.IsNullOrWhiteSpace(sort.SortName))
                    {
                        continue;
                    }
                    MemberExpression body = Expression.PropertyOrField(parameter, sort.SortName);
                    sourceExpression = Expression.Call(typeof(Queryable), sort.SortType == SortType.Asc ? methodAsc : methodDesc, new Type[] { typeof(TEntity), body.Type }, sourceExpression, Expression.Quote(Expression.Lambda(body, parameter)));
                    methodAsc = "ThenBy";
                    methodDesc = "ThenByDescending";
                }
            }

            //query = query.Provider.Execute<IEnumerable<TEntity>>(sourceExpression).AsQueryable();
            var data = query.Provider.Execute<IEnumerable<TEntity>>(sourceExpression).ToList();

            result.TotalCount = data.Count;
            if (input.PageSize != -1)
            {
                var res = data.Skip((input.PageIndex - 1) * input.PageSize).Take(input.PageSize);

                result.PageIndex = input.PageIndex;
                result.PageSize = input.PageSize;
                result.TotalPages %= input.PageSize;
                result.Items = res;
                result.HasPrevPages = input.PageIndex > 1 && input.PageIndex <= 2;
                result.HasNextPages = input.PageIndex < result.TotalPages;
            }
            else
            {
                result.PageIndex = input.PageIndex;
                result.PageSize = input.PageSize;
                result.TotalPages %= input.PageSize;
                result.Items = data;
                result.HasPrevPages = input.PageIndex > 1 && input.PageIndex <= 2;
                result.HasNextPages = input.PageIndex < result.TotalPages;
            }

            return result;
        }

        #endregion

        #region == 异步 ==

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<long> InsertSync(TEntityInputDto input) => await _db.Insertable<TEntity>(input).IgnoreColumns(ignoreNullColumn: true).ExecuteReturnBigIdentityAsync();
        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<int> UpdateSync(TEntityUpdateDto input) => await _db.Updateable<TEntity>(input).ExecuteCommandAsync();

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<int> DelectSync(TEntityDeleteDto input) => await _db.Updateable<TEntity>(input).ExecuteCommandAsync();

        /// <summary>
        /// 清除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<int> ClearSync(int id) => await _db.Deleteable<TEntity>(id).ExecuteCommandAsync();

        /// <summary>
        /// 单条查询（根据主键）
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<TEntity> FindSync(int id) => await _db.Queryable<TEntity>().InSingleAsync(id);
        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public async Task<PagedList<TEntity>> GetAllByPageSync(int pageIndex = 1, int pageSize = 10)
        {
            RefAsync<int> totalCount = 0;
            PagedList<TEntity> result = new();
            var data = await _db.Queryable<TEntity>().ToPageListAsync(pageIndex, pageSize, totalCount);
            result.PageIndex = pageIndex;
            result.PageSize = pageSize;
            result.TotalCount = totalCount;
            result.TotalPages = totalCount % pageSize;
            result.Items = data;
            result.HasPrevPages = pageIndex > 1 && pageIndex <= 2;
            result.HasNextPages = pageIndex < result.TotalPages;
            return result;
        }

        /// <summary>
        /// 分页条件查询
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedList<TEntity>> GetSearchSync([FromQuery] TCondition input)
        {
            var result = new PagedList<TEntity>();

            var list = await  _db.Queryable<TEntity>().ToListAsync();
            var query = list.AsQueryable();
            var sourceExpression = query.Expression;


            if (input.Filters != null)
            {
                var Filters = JsonConvert.DeserializeObject<List<DataFilter>>(input.Filters);
                foreach (var filter in Filters)
                {
                    if (string.IsNullOrWhiteSpace(filter.FilterName) || string.IsNullOrWhiteSpace(filter.FilterValue))
                    {
                        continue;
                    }
                    var whereLambdaExtenstion = GetLambdaExtention(filter);
                    sourceExpression = Expression.Call(typeof(Queryable), "Where", new Type[1] { typeof(TEntity) }, sourceExpression, Expression.Quote(whereLambdaExtenstion.GetLambda()));

                }
            }
            if (input.Sorts != null)
            {
                var Sorts = JsonConvert.DeserializeObject<IList<DataSort>>(input.Sorts);
                ParameterExpression parameter = Expression.Parameter(typeof(TEntity), "x");
                string methodAsc = "OrderBy";
                string methodDesc = "OrderByDescending";
                foreach (var sort in Sorts)
                {
                    if (string.IsNullOrWhiteSpace(sort.SortName))
                    {
                        continue;
                    }
                    MemberExpression body = Expression.PropertyOrField(parameter, sort.SortName);
                    sourceExpression = Expression.Call(typeof(Queryable), sort.SortType == SortType.Asc ? methodAsc : methodDesc, new Type[] { typeof(TEntity), body.Type }, sourceExpression, Expression.Quote(Expression.Lambda(body, parameter)));
                    methodAsc = "ThenBy";
                    methodDesc = "ThenByDescending";
                }
            }

            //query = query.Provider.Execute<IEnumerable<TEntity>>(sourceExpression).AsQueryable();
            var data = query.Provider.Execute<IEnumerable<TEntity>>(sourceExpression).ToList();

            result.TotalCount = data.Count;
            if (input.PageSize != -1)
            {
                var res = data.Skip((input.PageIndex - 1) * input.PageSize).Take(input.PageSize);

                result.PageIndex = input.PageIndex;
                result.PageSize = input.PageSize;
                result.TotalPages %= input.PageSize;
                result.Items = res;
                result.HasPrevPages = input.PageIndex > 1 && input.PageIndex <= 2;
                result.HasNextPages = input.PageIndex < result.TotalPages;
            }
            else
            {
                result.PageIndex = input.PageIndex;
                result.PageSize = input.PageSize;
                result.TotalPages %= input.PageSize;
                result.Items = data;
                result.HasPrevPages = input.PageIndex > 1 && input.PageIndex <= 2;
                result.HasNextPages = input.PageIndex < result.TotalPages;
            }

            return result;
        }

        #endregion

        #region ==工具==
        //Lambda表达式处理
        private static LambdaExtention<TEntity> GetLambdaExtention(DataFilter filter)
        {
            var whereLambdaExtenstion = new LambdaExtention<TEntity>();

            switch (filter.FilterType)
            {
                case FilterType.Int:
                    whereLambdaExtenstion.GetExpression(filter.FilterName, int.Parse(filter.FilterValue), filter.ExpressionType);
                    break;
                case FilterType.Long:
                    whereLambdaExtenstion.GetExpression(filter.FilterName, long.Parse(filter.FilterValue), filter.ExpressionType);
                    break;
                case FilterType.Boolean:
                    whereLambdaExtenstion.GetExpression(filter.FilterName, filter.FilterValue.ToUpper() == "TRUE", filter.ExpressionType);
                    break;
                default:
                    whereLambdaExtenstion.GetExpression(filter.FilterName, filter.FilterValue, filter.ExpressionType);
                    break;
            }
            return whereLambdaExtenstion;

        }
        #endregion
    }

    /// <summary>
    /// 增删查改父类（Dapper）
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TEntityInputDto"></typeparam>
    /// <typeparam name="TEntityUpdateDto"></typeparam>
    /// <typeparam name="TEntityDeleteDto"></typeparam>
    /// <typeparam name="TCondition"></typeparam>
    public class CurdService_Dapper<TEntity, TEntityInputDto, TEntityUpdateDto, TEntityDeleteDto, TCondition>
        where TEntity : class, IPrivateEntity, new()
        where TCondition : PagedBaseDto
    {
        /// <summary>
        /// 注入仓储
        /// </summary>
        private readonly IDapperRepository _dapperRepository;

        /// <summary>
        /// 构造函数
        /// </summary>
        public CurdService_Dapper(IDapperRepository dapperRepository)
        {
            _dapperRepository = dapperRepository;
        }


    }
}
